<?php
// +----------------------------------------------------------------------
// | Author: July
// +----------------------------------------------------------------------
// | 创建时间: 2023-12-27 20:39:42
// +----------------------------------------------------------------------
// | 公共认证类
// +----------------------------------------------------------------------

namespace july\julyadmin\admin\controller;

use july\julyadmin\common\model\Admin;
use july\julyadmin\common\model\AdminRoleList;
use july\julyadmin\common\model\Config;
use july\julyadmin\common\model\Menu;
use think\exception\HttpResponseException;
use think\Response;

class Auth
{

    /**
     * 无需登录的控制器和方法列表
     * 不区分大小写，下面验证的时候会做处理
     * 如：$noNeedLogin = ['index']
     */
    protected $noNeedLogin = ['*'];
    /**
     * 无需验证权限的控制器和方法列表
     * 不区分大小写，下面验证的时候会做处理
     * 如：$noNeedLogin = ['index']
     */
    protected $noPermissionAuth = [];

    /**
     * 初始化
     */
    protected function initialize()
    {
        $app_map = config('app.app_map', []);
        $module  = 'admin';
        if ($app_map) {
            if ($key = array_search($module, $app_map)) {
                $module = $key;
            }
        }

        $controller = strtolower(request()->controller());
        $action     = strtolower(request()->action());

        if ($this->noNeedLogin) {
            //如果不需要验证登录权限的控制器和方法不为空，那么对其引用自定义方法全部转换为小写
            array_walk($this->noNeedLogin, function (&$value, $key) {
                $value = strtolower($value);
            });
        }

        $this->noPermissionAuth = array_merge($this->noPermissionAuth, ['selectTree', 'selectPage']);
        if ($this->noPermissionAuth) {
            //如果不需要验证权限的控制器和方法不为空，那么对其引用自定义方法全部转换为小写
            array_walk($this->noPermissionAuth, function (&$value, $key) {
                $value = strtolower($value);
            });
        }

        if (!session('admininfo') && !in_array($action, $this->noNeedLogin) && !in_array('*', $this->noNeedLogin)) {
            $this->error("请重新登陆", url('/' . $module . '/Index/login'));
            exit;
        }

        if (session('admininfo')) {
            $admin = Admin::where(['id' => session('admininfo.id')])->find();
            if (!$admin) {
                session('admininfo', null);
                $this->error("请重新登陆", url('/' . $module . '/Index/login'));
                exit;
            }
            if ($admin['disabled'] == 0) {
                session('admininfo', null);
                $this->error("账户被禁用", url('/' . $module . '/Index/login'));
                exit;
            }
        }

        
        if (session('admininfo') && session('admininfo.roleid') != 1 && !in_array($action, $this->noPermissionAuth) && !in_array('*', $this->noPermissionAuth)) {
            //验证是否有操作权限

            //判断操作菜单权限
            $menu_permission = Menu::alias('menu')->where(['menu.controller' => $controller, 'menu.action' => $action])->where("(SELECT COUNT(0) FROM " . Config("database.connections.mysql.prefix") . "admin_role_list L WHERE L.role_id='" . session('admininfo.roleid') . "' AND (FIND_IN_SET(menu.id,L.menu_parent_ids) OR menu.id=L.menu_id)>0)")->count();
            //判断操作按钮权限
            $button_permission = AdminRoleList::where(['controller' => $controller, 'action' => $action, 'role_id' => session('admininfo.roleid')])->count();
            if (!$menu_permission && !$button_permission) {
                $info = ['code' => '401', 'msg' => '没有操作权限'];
                if (request()->isAjax()) {
                    $this->error("没有操作权限");
                    exit;
                } else {
                    $type     = 'view';
                    $response = Response::create(app()->getRootPath() . '/vendor/july/julyadmin/src/admin/view/error/error.html', $type)->assign(['info' => $info])->header([]);
                    throw new HttpResponseException($response);
                }
            }
        }

        //记录操作日志
        $this->writeLog();
    }

    /**
     * 写入操作日志
     */
    public function writeLog()
    {
        if (!session('admininfo')) {
            return false;
        }
        //请求类型
        $method = strtolower(request()->method());
        //当前请求方法
        $action = strtolower(request()->action());
        //配置允许写入日志的请求类型
        $admin_write_log_method = Config::config('System.admin_write_log_method');
        if (!$admin_write_log_method) {
            $admin_write_log_method = [];
        } else {
            $admin_write_log_method = explode(',', $admin_write_log_method);
        }

        //判断请求类型是否需要记录
        if (!in_array($method, $admin_write_log_method)) {
            return false;
        }

        //配置需要排除写入日志的方法
        $admin_write_log_exclude_action = Config::config('System.admin_write_log_exclude_action');
        if ($admin_write_log_exclude_action) {
            $admin_write_log_exclude_action = explode(',', $admin_write_log_exclude_action);
        } else {
            $admin_write_log_exclude_action = [];
        }

        $admin_write_log_exclude_action = array_merge($admin_write_log_exclude_action, [
            'index',
            'selectPage',
            'selectTree',
        ]);

        //如果不需要验证登录权限的控制器和方法不为空，那么对其引用自定义方法全部转换为小写
        array_walk($admin_write_log_exclude_action, function (&$value, $key) {
            $value = strtolower($value);
        });

        //如果当前访问方法在排除列表中，则不写入日志
        if (in_array($action, $admin_write_log_exclude_action)) {
            return false;
        }

        //配置需要排除写入日志的字段
        $admin_write_log_exclude_field = Config::config('System.admin_write_log_exclude_field');
        if ($method == 'post') {
            $content = input('post.');
        } else {
            $content = [];
        }

        //去除提交数据中的指定字段
        if ($admin_write_log_exclude_field) {
            $admin_write_log_exclude_field = explode(',', $admin_write_log_exclude_field);
            foreach ($content as $k => $v) {
                if (in_array($k, $admin_write_log_exclude_field)) {
                    unset($content[$k]);
                }
            }
        }

        $url = (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443') ? 'https://' : 'http://';
        $url .= $_SERVER['HTTP_HOST'];
        $url .= isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : urlencode($_SERVER['PHP_SELF']) . '?' . urlencode($_SERVER['QUERY_STRING']);

        $data = [
            'url'    => $url,
            'method' => $method,
            'data'   => json_encode($content),
            'userid' => session('admininfo.id'),
            'ip'     => request()->ip(),
        ];

        $OperationLog = new \july\julyadmin\common\model\OperationLog;
        $OperationLog->save($data);
    }
}
